package com.ksd.pug.service.user;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ksd.orm.pug.mapper.SysLoginUserMapper;
import com.ksd.pug.commons.enums.ResultStatusEnumA;
import com.ksd.pug.commons.ex.PugBussinessException;
import com.ksd.pug.commons.utils.collection.CollectionUtils;
import com.ksd.pug.commons.utils.fn.asserts.Vsserts;
import com.ksd.pug.pojo.Permission;
import com.ksd.pug.pojo.RoleUser;
import com.ksd.pug.pojo.SysLoginUser;
import com.ksd.pug.pojo.SysRole;
import com.ksd.pug.service.jwt.JwtBlackStringService;
import com.ksd.pug.service.permission.IPermissionService;
import com.ksd.pug.service.roleuser.IRoleUserService;
import com.ksd.pug.vo.RoleUserVo;
import com.ksd.pug.vo.TreeVo;
import com.ksd.pug.vo.user.UserVo;
import com.pug.redis.config.PugRedisCacheTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author: hcl
 * @date: 2022/1/24 15:06
 * @Description:
 */
@Slf4j
@Service
public class SysLoginUserServiceImpl extends ServiceImpl<SysLoginUserMapper, SysLoginUser> implements ISysLoginUserService {

    @Autowired
    private IPermissionService permissionService;

    @Autowired
    private IRoleUserService roleUserService;

    @Autowired
    private PugRedisCacheTemplate pugRedisCacheTemplate;
    @Autowired
    private JwtBlackStringService jwtBlackListService2;
    /**
     * 根据用户手机号码查询用户
     * @param phone
     * @return
     */
    @Override
    public SysLoginUser getByPhone(String phone) {
        LambdaQueryWrapper<SysLoginUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysLoginUser::getTelephone, phone);
        return this.getOne(lambdaQueryWrapper);
    }
    /**
     * 根据用户名查询用户
     * @param username
     * @return
     */
    @Override
    public SysLoginUser getByUsername(String username) {
        LambdaQueryWrapper<SysLoginUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysLoginUser::getUsername, username);
        return this.getOne(lambdaQueryWrapper);
    }
    /**
     * 查询用户表信息并分页
     *
     * @return
     */
    @Override
    public IPage<SysLoginUser> findUserPage(UserVo userVo) {
        // 1: 设置分页
        Page<SysLoginUser> page = new Page<>(userVo.getPageNo(), userVo.getPageSize());
        // 2: 设置条件
        LambdaQueryWrapper<SysLoginUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 3：查询过滤一些字段，为啥要这样做呢？因为在开放中很多时候，我们一些表存在大字段列，而这些返回的过程非常非常查询性能。
        lambdaQueryWrapper.select(SysLoginUser.class,column -> !column.getColumn().equals("password"));
        lambdaQueryWrapper.select(SysLoginUser.class,column -> !column.getColumn().equals("idcard"));
        lambdaQueryWrapper.select(SysLoginUser.class,column -> !column.getColumn().equals("openid"));
        // 4: 把未删除的查询出来，那些删除的数据可以做一个回收站去回收即可
        lambdaQueryWrapper.eq(SysLoginUser::getIsdelete, userVo.getIsDelete());
        //超级管理不用显示
        lambdaQueryWrapper.ne(SysLoginUser::getId,1L);

        // 5:根据名字进行模糊匹配
        // 多列搜索
        lambdaQueryWrapper.and(Vsserts.isNotEmpty(userVo.getKeyword()),wrapper -> wrapper
                .like(SysLoginUser::getUsername, userVo.getKeyword())
                .or()
                .like(SysLoginUser::getNickname, userVo.getKeyword())
        );

        // 条件拼接分类
        lambdaQueryWrapper.eq(Vsserts.isNotNull(userVo.getStatus()),SysLoginUser::getStatus,userVo.getStatus());

        // 6: 设置排序 ，最新的放在最前
        lambdaQueryWrapper.orderByAsc(SysLoginUser::getCreateTime);
        Page<SysLoginUser> userPage = this.page(page, lambdaQueryWrapper);
        List<SysLoginUser> userList = userPage.getRecords();
        userList.forEach(type->{
            //查询用户对应角色
            List<SysRole> roleList = this.findSysRoleByUserId(type.getId());
            String roles;
            List<Long> rolelists = new ArrayList<>();
            if(null == roleList || roleList.size() ==0){
                roles="普通用户";
            }
            else{
                List<String> collect = roleList.stream().map(SysRole::getName).collect(Collectors.toList());
                roles = String.join(",", collect);
                rolelists = roleList.stream().map(SysRole::getId).collect(Collectors.toList());


            }
            type.setRolelists(rolelists);
            type.setRoles(roles);
        });
        userPage.setRecords(userList);
        // 7：最后返回
        return userPage;
    }
    /**
     * 保存和修改用户
     *
     * @param sysLoginUser
     */
    @Override
    public SysLoginUser saveUpdateUser(SysLoginUser sysLoginUser) {
        return this.saveOrUpdate(sysLoginUser) ? sysLoginUser : null;
    }
    /**
     * 根据用户id删除用户
     *
     * @param id
     * @return
     */
    @Override
    public boolean delUser(Long id) {
        return this.removeById(id);
    }
    /**
     * 根据用户ids删除用户
     *
     * @param ids
     * @return
     */
    @Override
    public boolean delBatchUser(String ids) {
        try {
            // 1 : 把数据分割
            String[] strings = ids.split(",");
            // 2: 组装成一个List<SysLoginUser>
            List<SysLoginUser> userList = Arrays.stream(strings).map(idstr -> {
                SysLoginUser sysLoginUser = new SysLoginUser();
                sysLoginUser.setId(new Long(idstr));
                sysLoginUser.setIsdelete(1);
                return sysLoginUser;
            }).collect(Collectors.toList());
            // 3: 批量删除
            return this.updateBatchById(userList);
        } catch (Exception ex) {
            throw new PugBussinessException(ResultStatusEnumA.IDS_ERROR_STATUS);
        }
    }
    /**
     * 根据用户id查询用户
     *
     * @param id
     * @return
     */
    @Override
    public SysLoginUser getUser(Long id) {
        return this.getById(id);
    }
    /**
     * 根据用户查询对应的角色
     * @param userid
     * @return
     */
    @Override
    public List<SysRole> findSysRoleByUserId(Long userid) {
        return this.baseMapper.findSysRoleByUserId(userid);
    }
    /**
     * 查询用户对应的权限
     * @param userid
     * @return
     */
    @Override
    public List<Permission> findBySysPermissionUserId(Long userid){
        //如果是超级管理员
        if(userid == 1L){
            List<Permission> permissionTree = permissionService.findPermissionTree();
            return permissionTree;
        }
        //查询所有
        List<Permission> sysPermissionList = this.baseMapper.findBySysPermissionUserId(userid);
        //查询所有父
        List<Permission> sysPermission = sysPermissionList.stream()
                .filter(c -> c.getPid().equals(0L)).collect(Collectors.toList());
        //根据当前的id去找对应的子集
        sysPermission.forEach(item -> {
            // 找到每个父元素的子集
            List<Permission> childrenList = sysPermissionList.stream()
                    .filter(c -> item.getId().equals(c.getPid())).collect(Collectors.toList());
            // 如果为空，代表没有匹配带子元素，就放一个空集合进去，目的：保证数据解构的完整性，已经方便后续前台的判断
            if (CollectionUtils.isEmpty(childrenList)) {
                childrenList = new ArrayList<>();
            }
            item.setChildrens(childrenList);
        });
        sysPermission = sysPermission.stream().sorted(Comparator.comparing(Permission::getIndexon)).collect(Collectors.toList());
        return sysPermission;
    }

    /**
     * 实现了多表关联查询分页
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public IPage<SysLoginUser> findLoginUserPage(int pageNo, int pageSize) {
        Page<SysLoginUser> page = new Page<>(pageNo, pageSize);
        QueryWrapper<SysLoginUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("su.status", 1);
        //queryWrapper.eq("su.isdelete", 0);
        return this.baseMapper.findLoginUserPage(page, queryWrapper);
    }
    /**
     * 查询用户对应的权限 树形
     * @param userid
     * @return
     */
    @Override
    public List<TreeVo> getTreeList(Long userid) {
        List<Permission> permissionUser = this.findBySysPermissionUserId(userid);

        List<TreeVo> collect = permissionUser.stream().map(type -> {
            TreeVo treevo = new TreeVo();
            treevo.setId(type.getId());
            treevo.setLabel(type.getTitle());
            if (Vsserts.isNotNull(type.getChildrens())) {
                //将子数组也转换为tree
                List<TreeVo> treeVos = PojiToVo(type.getChildrens());
                treevo.setChildren(treeVos);
            }
            return treevo;
        }).collect(Collectors.toList());
        return collect;
    }

    //将子数组也转换为tree
    private List<TreeVo> PojiToVo(List<Permission> pojo){
        return  pojo.stream().map(children -> {
            TreeVo tree = new TreeVo();
            tree.setId(children.getId());
            tree.setLabel(children.getTitle());
            return tree;
        }).collect(Collectors.toList());
    }
    //根据角色名称 保存 用户 对应的 角色
    @Override
    public boolean saveUserRole(RoleUserVo roleUserVo) {
        //根据userId删除原数据
        roleUserService.remove(new LambdaQueryWrapper<RoleUser>()
                .eq(RoleUser::getUserId,roleUserVo.getUserId()));

        List<Long> listIds = Arrays.asList(roleUserVo.getIds().split(",")).stream().map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
        //批量添加
        List<RoleUser> collect = listIds.stream().map(type -> {
            RoleUser roleUser = new RoleUser();
            roleUser.setRoleId(type);
            roleUser.setUserId(roleUserVo.getUserId());
            return roleUser;
        }).collect(Collectors.toList());
        roleUserService.saveBatch(collect);

        //如果用户权限修改则把用户token拉黑，让他重新登录
        String token = pugRedisCacheTemplate.getCacheObject("sys:user:token:" + roleUserVo.getUserId());
        // 把当前token拉入黑名单中
        jwtBlackListService2.addBlackList(token);
        // 删除缓存
        pugRedisCacheTemplate.deleteObject("sys:user:permission:list:"+token);
        return true;
    }


}
